home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
pctjsp86.arc
/
KWIKKEY.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-07-01
|
11KB
|
255 lines
;-----------------------------------------------------------------
; KWIKKEY.ASM Version 1.4 5-28-86
; Copyright (c) 1985 by Dan Rollins
;
; This program speeds up the repeat action of the IBM PC and XT
; keyboard. After installation, a keystroke begins repeating about
; 1/4 second after the initial keystroke and the repeats occur at
; about twice the normal speed. These delay and rate parameters may
; be modified. The program uses the 55ms timer interrupt to augment
; the speed of the keyboard. The basic idea is to have the timer
; interrupt check to see if the key has been released. If not, then
; it stuffs a keystroke into the BIOS keyboard buffer. Notes: This
; program must be used with DOS 2.x or later. It is a COM format
; program, so it must be processed by EXE2BIN.
;------------------------------------------------------------------
;=== program equates ===
REPT_DELAY equ 5 ;number of 55ms intervals to skip before
; the first repeat. 5 = 275ms = about
; 1/4 second. Use at least 2 to avoid
; "key bounce"
REPT_RATE equ 1 ;Select from: 0 = 29 repeats per second
; 1 = 20 repeats per second
; 2 = 16 repeats per second
; 3 = 13 repeats per second
; 4 or more = standard repeat rate
BIOS_DATA_SEG equ 40h ;These addresses are listed
BUF_START equ 1eh ; in the Technical Reference manual
BUF_END equ 3eh
BUF_HEAD_ADDR equ 1ah
BUF_TAIL_ADDR equ 1ch
ALT_NUM_BUF equ 19h
FALSE equ 0
TRUE equ 1
;=========================
com_seg segment
assume cs:com_seg, ds:com_seg
org 100h ;must set up for COM file
kwikkey proc far
jmp set_up ;get past the data and install the
;interrupt handlers
;============= program data area ========
delay db REPT_DELAY ;max ticks BEFORE STARTING to repeat
rate db REPT_RATE ;maximum ticks BETWEEN repeats
inst_flag dw 1234h ;KWIKKEY signature when already installed
rep_ok db FALSE ;flag turns off repeat while processing
last_key dw 0 ;stores most recent keyboard scan code
init_delay db REPT_DELAY ;remaining ticks before
;starting to repeat
rate_delay db REPT_RATE ;remaining tick between repeats
bios_kbd_int label dword ;DWORD so it can be used in a FAR call
bki_offset dw 0 ; This is set to the addr of BIOS KB_INT
bki_segment dw 0 ; at the time of installation of KWIKKEY
user_timer_int label dword ;used to preserve "forward chain" of user
uti_offset dw 0 ;timer interrupt handlers. Set in SET_UP
uti_segment dw 0 ;procedure, this addr will normally point
;to an IRET.
;---------------------------------------------------------------------
; KBD_INT
; This procedure intercepts keystrokes and sends control to normal
; BIOS KB_INT. Its primary function is to set up for the repeat action
; that occurs in the TIMER_INT. It checks each key that comes in, and
; resets a delay counter if it is a new keystroke.
kbd_int proc far
mov cs:rep_ok,FALSE ;turn off repeats while
;processing
push ax ;save the registers
push si
push ds
mov ax,BIOS_DATA_SEG ; set up to address
mov ds,ax ; BIOS data area
mov si,ds:[BUF_TAIL_ADDR] ;get addr of current
;buffer tail
;check special case: don't repeat ALT-numpad keystrokes
cmp byte ptr ds:[ALT_NUM_BUF],0 ;is one in progress?
je ki_10 ; no, continue
pushf ; yes, process
call cs:bios_kbd_int ; the keystroke
jmp ki_exit ; exit with repeats off
ki_10:
pushf ;simulate a normal interrupt
call cs:bios_kbd_int ; and process the keystroke
cmp si,ds:[BUF_TAIL_ADDR] ;did the tail move?
jne ki_20 ; no, either a shift-key
; or a release
mov cs:last_key,0 ; insure no spurious repeats
jmp ki_exit ; exit with repeats turned off
ki_20: ; yes, process the keystroke
mov ax,[si] ; get new scan code
cmp ax,cs:[last_key] ; same as last time?
mov cs:last_key,ax ; (save the key for next time)
je ki_30 ; yes, hardware repeat
; just reset the rate
; no, reset both timer delays
mov al,cs:delay ; get maximum tick count
mov cs:init_delay,al ; set delay before repeat
ki_30:
mov al,cs:rate ; get maximum tick value
mov cs:rate_delay,al ; set delay between repeats
mov cs:rep_ok,TRUE ; OK to continue repeating
ki_exit:
pop ds
pop si
pop ax
iret ;also restores Flags of interruptee
kbd_int endp
;---------------------------------------------------------------------
; TIMER_INT
; This procedure is executed 18.2 times per second
;
; It checks to see if a repeat is needed. If so, it stuffs the scan
; code into the keyboard buffer, ready for the next keystroke request
;
timer_int proc far
cmp cs:[rep_ok],TRUE ;are repeats blocked?
jne ti_exit ; yes, resume without repeat
cmp cs:init_delay,0 ;finished delaying before
;first repeat?
je ti_10 ; yes, check rate delay
dec cs:init_delay ; no, decrement timer
jmp ti_exit ; and resume without repeat
ti_10:
cmp cs:rate_delay,0 ;finished delaying between repeats?
je ti_20 ; yes, do the repeat
dec cs:rate_delay ; no, decrement rate timer
jmp ti_exit ; and resume without repeat
;------- repeat the previous keystroke -----------
ti_20:
push ax ;save all registers used
push si
push ds
mov ax,BIOS_DATA_SEG ;prepare to address BIOS data area
mov ds,ax
mov ax,ds:[BUF_TAIL_ADDR] ;get current position
;in kbd buffer
mov si,ax ;we'll need this address later
add ax,2 ;point to next position in buffer
cmp ax,BUF_END ;past end of buffer?
jne ti_30 ; no, continue
mov ax,BUF_START ; yes, next position is the
;start
ti_30:
cmp ax,ds:[BUF_HEAD_ADDR] ;if tail=head, buffer is full
je ti_40 ;full, continue without repeat
cli ;not full, dont allow break-in
mov ds:[BUF_TAIL_ADDR],ax ; update buffer position
mov ax,cs:[last_key] ; fetch key to repeat
mov [si],ax ; store key in buffer
sti ; interrupts ok now
ti_40:
mov al,cs:rate ;get the max rate delay value
mov cs:rate_delay,al ;don't repeat for a while
pop ds ;restore registers
pop si ; and exit
pop ax
ti_exit:
jmp cs:[user_timer_int] ;continue with previously
;installed interrupt handler
timer_int endp
LAST_BYTE equ offset $+1 ;this is the address passed to INT 27H
; Notice that the code of the SET_UP
; procedure does not need to be preserved
;---------------------------------------------------------------------
; SET_UP
; This routine is executed only once -- when the program is installed.
;
; It resets the vectors of the KBD_INT and the USER_TIMER_INT,
; pointing them to code within this program. Note that the original
; vectors are saved and executed so all previously-installed interrupt
; handlers remain operational.
logo_msg db 201, 25 dup(205),187,0dh,0ah
db 186,' KWIKKEY Ver. 1.4 ',186,0dh,0ah
db 186,' (c) 1986 by Dan Rollins ',186,0dh,0ah
db 200, 25 dup(205),188,0dh,0ah,'$'
err_msg db 'Error: ',07,'KWIKKEY already installed',0dh,0ah,'$'
set_up proc near
;------ first, make sure KWIKKEY hasn't been installed ---
mov al,9
mov ah,35h ;DOS GET_VECTOR service
int 21h ; for interrupt 9
cmp es:inst_flag,1234h ;has KWIKKEY been installed?
jne su_10 ; no, continue
mov dx,offset err_msg ; yes, display
mov ah,9 ; error
int 21h ; message
int 20h ;and exit to DOS
su_10:
mov al,9 ;get original vector of keyboard int 9
mov ah,35h ;DOS GET_VECTOR service
int 21h
mov bki_segment,es ;save original address
mov bki_offset,bx ; so we can resume normally
; after intercept
mov dx,offset kbd_int
mov al,9 ;set vector for INT 9
mov ah,25h ;DOS SET_VECTOR service
int 21h
mov al,1ch ;the user timer interrupt
mov ah,35h ;DOS GET_VECTOR service
int 21h
mov uti_segment,es ;save old address
mov uti_offset,bx ; so we don't hog the timer interrupt
mov dx,offset timer_int
mov al,1ch ;set vector to point to new TIMER_INT
mov ah,25h ;DOS SET_VECTOR service
int 21h
;------ display logo to indicate installation complete
mov dx,offset logo_msg
mov ah,9
int 21h
mov cs:rep_ok,TRUE ; it's OK to start repeat action
;------ exit to DOS, leaving the interrupt handlers resident
mov dx,LAST_BYTE
int 27h
set_up endp
kwikkey endp
com_seg ends
end kwikkey ;must specify for COM-format file